package com.geo.auth.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.geo.auth.dto.LoginRequest;
import com.geo.auth.dto.LoginResponse;
import com.geo.auth.dto.RegisterRequest;
import com.geo.auth.dto.UserInfoResponse;
import com.geo.auth.entity.Role;
import com.geo.auth.entity.User;
import com.geo.auth.entity.UserRole;
import com.geo.auth.mapper.RoleMapper;
import com.geo.auth.mapper.UserMapper;
import com.geo.auth.mapper.UserRoleMapper;
import com.geo.common.exception.BusinessException;
import com.geo.common.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 认证服务类
 * 
 * @author GEO Team
 * @version 1.0
 */
@Slf4j
@Service
public class AuthService {
    
    private static final Logger log = LoggerFactory.getLogger(AuthService.class);
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private RoleMapper roleMapper;
    
    @Autowired
    private UserRoleMapper userRoleMapper;
    
    // 最大登录失败次数
    private static final int MAX_LOGIN_FAILURE_COUNT = 5;
    
    // 账户锁定时长（分钟）
    private static final int LOCK_DURATION_MINUTES = 30;
    
    /**
     * 用户登录
     * @param request 登录请求
     * @return 登录响应
     */
    @Transactional
    public LoginResponse login(LoginRequest request) {
        // 参数校验
        if (StrUtil.isBlank(request.getUsername()) || StrUtil.isBlank(request.getPassword())) {
            throw new BusinessException(ResultCode.INVALID_PARAM, "用户名和密码不能为空");
        }
        
        // 查询用户
        User user = userMapper.selectByUsername(request.getUsername());
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND, "用户不存在");
        }
        
        // 检查用户状态
        checkUserStatus(user);
        
        // 验证密码
        String encryptedPassword = encryptPassword(request.getPassword());
        if (!encryptedPassword.equals(user.getPassword())) {
            // 密码错误，增加失败次数
            handleLoginFailure(user);
            throw new BusinessException(ResultCode.INVALID_CREDENTIALS, "密码错误");
        }
        
        // 登录成功，重置失败次数
        handleLoginSuccess(user, request.getClientIp());
        
        // 执行Sa-Token登录
        StpUtil.login(user.getId());
        
        // 获取用户角色和权限
        List<String> roles = getRolesByUserId(user.getId());
        List<String> permissions = getPermissionsByUserId(user.getId());
        
        // 构建响应
        return LoginResponse.builder()
                .token(StpUtil.getTokenValue())
                .tokenName(StpUtil.getTokenName())
                .userId(user.getId())
                .username(user.getUsername())
                .nickname(user.getNickname())
                .avatar(user.getAvatar())
                .userType(user.getUserType().getCode())
                .roles(roles)
                .permissions(permissions)
                .expiresIn(StpUtil.getTokenTimeout())
                .build();
    }
    
    /**
     * 用户注册
     * @param request 注册请求
     * @return 用户信息
     */
    @Transactional
    public User register(RegisterRequest request) {
        // 参数校验
        validateRegisterRequest(request);
        
        // 检查用户名是否已存在
        if (userMapper.selectByUsername(request.getUsername()) != null) {
            throw new BusinessException(ResultCode.USER_ALREADY_EXISTS, "用户名已存在");
        }
        
        // 检查邮箱是否已存在
        if (StrUtil.isNotBlank(request.getEmail()) && userMapper.selectByEmail(request.getEmail()) != null) {
            throw new BusinessException(ResultCode.EMAIL_ALREADY_EXISTS, "邮箱已被使用");
        }
        
        // 创建用户
        User user = User.builder()
                .username(request.getUsername())
                .password(encryptPassword(request.getPassword()))
                .email(request.getEmail())
                .phone(request.getPhone())
                .nickname(request.getNickname())
                .userType(User.UserType.MERCHANT) // 默认为商家用户
                .status(User.UserStatus.ACTIVE)
                .loginFailureCount(0)
                .build();
        
        userMapper.insert(user);
        
        // 分配默认角色
        assignDefaultRole(user.getId());
        
        log.info("用户注册成功: {}", user.getUsername());
        
        return user;
    }
    
    /**
     * 用户登出
     */
    public void logout() {
        String userId = StpUtil.getLoginIdAsString();
        StpUtil.logout();
        log.info("用户登出: {}", userId);
    }
    
    /**
     * 获取当前用户信息
     * @return 用户信息
     */
    public UserInfoResponse getCurrentUser() {
        String userId = StpUtil.getLoginIdAsString();
        User user = userMapper.selectById(userId);
        
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_FOUND, "用户不存在");
        }
        
        List<String> roles = getRolesByUserId(userId);
        List<String> permissions = getPermissionsByUserId(userId);
        
        return UserInfoResponse.builder()
                .userId(user.getId())
                .username(user.getUsername())
                .nickname(user.getNickname())
                .email(user.getEmail())
                .phone(user.getPhone())
                .avatar(user.getAvatar())
                .userType(user.getUserType().getCode())
                .status(String.valueOf(user.getStatus().getCode()))
                .roles(roles)
                .permissions(permissions)
                .lastLoginTime(user.getLastLoginTime())
                .createdAt(user.getCreatedAt())
                .build();
    }
    
    /**
     * 检查用户状态
     * @param user 用户
     */
    private void checkUserStatus(User user) {
        // 检查用户是否需要解锁
        if (user.shouldUnlock()) {
            user.resetLoginFailureCount();
            userMapper.updateById(user);
        }
        
        if (!user.isAvailable()) {
            if (user.getStatus() == User.UserStatus.LOCKED) {
                log.warn("账户已被锁定: {}", user.getUsername());
                throw new BusinessException(ResultCode.USER_LOCKED, "账户已被锁定，请稍后再试");
            } else if (user.getStatus() == User.UserStatus.DISABLED) {
                log.warn("账户已被禁用: {}", user.getUsername());
                throw new BusinessException(ResultCode.USER_DISABLED, "账户已被禁用");
            } else {
                log.warn("账户未激活: {}", user.getUsername());
                throw new BusinessException(ResultCode.USER_INACTIVE, "账户未激活");
            }
        }
    }
    
    /**
     * 处理登录失败
     * @param user 用户
     */
    private void handleLoginFailure(User user) {
        user.incrementLoginFailureCount(MAX_LOGIN_FAILURE_COUNT, LOCK_DURATION_MINUTES);
        userMapper.updateById(user);
        log.warn("用户登录失败，失败次数: {}, 用户名: {}", user.getLoginFailureCount(), user.getUsername());
    }
    
    /**
     * 处理登录成功
     * @param user 用户
     * @param clientIp 客户端IP
     */
    private void handleLoginSuccess(User user, String clientIp) {
        user.resetLoginFailureCount();
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(clientIp);
        userMapper.updateById(user);
        log.info("用户登录成功: {}", user.getUsername());
    }
    
    /**
     * 加密密码
     * @param password 原始密码
     * @return 加密后的密码
     */
    private String encryptPassword(String password) {
        return SecureUtil.md5(password + "geo_platform_salt");
    }
    
    /**
     * 验证注册请求
     * @param request 注册请求
     */
    private void validateRegisterRequest(RegisterRequest request) {
        if (StrUtil.isBlank(request.getUsername())) {
            throw new BusinessException(ResultCode.INVALID_PARAM, "用户名不能为空");
        }
        
        if (request.getUsername().length() < 3 || request.getUsername().length() > 50) {
            throw new BusinessException(ResultCode.INVALID_PARAM, "用户名长度必须在3-50个字符之间");
        }
        
        if (StrUtil.isBlank(request.getPassword())) {
            throw new BusinessException(ResultCode.INVALID_PARAM, "密码不能为空");
        }
        
        if (request.getPassword().length() < 6 || request.getPassword().length() > 50) {
            throw new BusinessException(ResultCode.INVALID_PARAM, "密码长度必须在6-50个字符之间");
        }
    }
    
    /**
     * 分配默认角色
     * @param userId 用户ID
     */
    private void assignDefaultRole(String userId) {
        Role defaultRole = roleMapper.selectDefaultRole();
        if (defaultRole != null) {
            UserRole userRole = UserRole.builder()
                    .userId(userId)
                    .roleId(defaultRole.getId())
                    .build();
            userRoleMapper.insert(userRole);
            log.info("为用户分配默认角色: {}, 角色: {}", userId, defaultRole.getRoleName());
        }
    }
    
    /**
     * 根据用户ID获取角色列表
     * @param userId 用户ID
     * @return 角色列表
     */
    private List<String> getRolesByUserId(String userId) {
        try {
            List<Role> roles = roleMapper.selectByUserId(userId);
            return roles.stream()
                    .map(Role::getRoleCode)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取用户角色失败: {}", userId, e);
            return List.of(); // 返回空列表而不是抛出异常
        }
    }
    
    /**
     * 根据用户ID获取权限列表
     * @param userId 用户ID
     * @return 权限列表
     */
    private List<String> getPermissionsByUserId(String userId) {
        try {
            return roleMapper.selectPermissionsByUserId(userId);
        } catch (Exception e) {
            log.error("获取用户权限失败: {}", userId, e);
            return List.of(); // 返回空列表而不是抛出异常
        }
    }
}